﻿namespace MicroCloud.AspNetCore.SignalR
{
    /// <summary>
    /// 业务实现：SignalR服务
    /// </summary>
    public class SignalRService : ISignalRService
    {
        #region "属性"
        #region "获取 服务提供者"
        /// <summary>
        /// 获取 服务提供者
        /// </summary>
        protected IServiceProvider ServiceProvider { get; }
        #endregion
        #region "获取 日志记录器"
        /// <summary>
        /// 获取 日志记录器
        /// </summary>
        protected ILogger Logger => ServiceProvider.GetLogger<SignalRService>();
        #endregion
        #region "获取 事件总线"
        /// <summary>
        /// 获取 事件总线
        /// </summary>
        protected IEventBus EventBus => ServiceProvider.GetService<IEventBus>();
        #endregion
        #region "获取 当前用户的基本功能"
        /// <summary>
        /// 获取 当前用户的基本功能
        /// </summary>
        protected IPrincipal Principal => ServiceProvider.GetService<IPrincipal>();
        #endregion

        #region "获取 通信连接用户缓存"
        /// <summary>
        /// 获取 通信连接用户缓存
        /// </summary>
        public IConnectionUserCache UserCache => ServiceProvider.GetService<IConnectionUserCache>();
        #endregion
        #region "获取 SignalR Hub(集线器)上下文"
        /// <summary>
        /// 获取 SignalR Hub(集线器)上下文
        /// </summary>
        public IHubContext<SignalRHub> SignalRHub => ServiceProvider.GetService<IHubContext<SignalRHub>>();
        #endregion

        #endregion

        #region "构造函数"
        #region "初始化一个业务实现：SignalR服务的新实例"
        /// <summary>
        /// 初始化一个业务实现：SignalR服务 <see cref="SignalRService"/> 的新实例
        /// </summary>
        /// <param name="provider">服务提供者</param>
        public SignalRService(IServiceProvider provider)
        {
            ServiceProvider = provider;
        }
        #endregion

        #endregion

        #region "方法"
        #region "加入组"
        /// <summary>
        /// 加入组
        /// </summary>
        /// <param name="connectionId">连接ID</param>
        /// <param name="groupKeys">组标识集合</param>
        /// <returns></returns>
        public virtual async Task<OperationResult> AddToGroup(string connectionId, params string[] groupKeys)
        {
            Check.NotNullOrEmpty(connectionId, nameof(connectionId));
            Check.NotNull(groupKeys, nameof(groupKeys));
            if (groupKeys?.Length <= 0)
            {
                return OperationResult.Error(I18N.T("组集合不能为空"));
            }
            if (groupKeys.ToList().Exists(m => m.IsMissing()))
            {
                return OperationResult.Error(I18N.T("组集合中组名不能为空"));
            }

            HubAddToGroupEventData eventData = new(SignalRHub.Clients, SignalRHub.Groups);

            //获取当前用户标识
            string userKey = GetCurrentUserKey();
            if (!userKey.IsMissing())
            {
                var user = await UserCache.GetUser(userKey);
                eventData.User = user;
                if (user == null || !user.ConnectionIds.Any(o => o == connectionId))
                {
                    throw new Exception(I18N.T("连接 {0} 无效", connectionId));
                }
            }

            foreach (string groupKey in groupKeys)
            {
                await SignalRHub.Groups.AddToGroupAsync(connectionId, groupKey);
                UserCache.AddUserGroup(userKey, groupKey, connectionId);
            }

            eventData.GroupKeys = groupKeys;
            eventData.ConnectionId = connectionId;
            //触发事件
            await EventBus?.PublishAsync(eventData);

            var msg = I18N.T("用户 {0}[{1}] 通过SignalR集线器加入组 {2}", userKey, connectionId, groupKeys.ExpandAndToString());
            Logger.LogDebug("{msg}", msg);
            return OperationResult.Success(msg);
        }
        #endregion
        #region "离开组"
        /// <summary>
        /// 离开组
        /// </summary>
        /// <param name="connectionId">连接ID</param>
        /// <param name="groupKeys">组标识集合</param>
        /// <returns></returns>
        public virtual async Task<OperationResult> RemoveFromGroup(string connectionId, params string[] groupKeys)
        {
            Check.NotNull(groupKeys, nameof(groupKeys));
            if (groupKeys?.Length <= 0)
            {
                return OperationResult.Error(I18N.T("组标识集合不能为空"));
            }
            if (groupKeys.ToList().Exists(m => m.IsMissing()))
            {
                return OperationResult.Error(I18N.T("组标识集合中组名不能为空"));
            }

            HubRemoveFromGroupEventData eventData = new(SignalRHub.Clients, SignalRHub.Groups);

            //获取当前用户标识
            string userKey = GetCurrentUserKey();
            if (!userKey.IsMissing())
            {
                var user = await UserCache.GetUser(userKey);
                eventData.User = user;
                if (user == null || !user.ConnectionIds.Any(o => o == connectionId))
                {
                    throw new Exception(I18N.T("连接 {0} 无效", connectionId));
                }
            }

            foreach (string groupKey in groupKeys)
            {
                await SignalRHub.Groups.RemoveFromGroupAsync(connectionId, groupKey);
                UserCache.RemoveUserGroup(userKey, groupKey, connectionId);
            }

            eventData.GroupKeys = groupKeys;
            eventData.ConnectionId = connectionId;
            //触发事件
            await EventBus?.PublishAsync(eventData);

            var msg = I18N.T("用户 {0}[{1}] 通过SignalR集线器离开组 {2}", userKey, connectionId, groupKeys.ExpandAndToString());
            Logger.LogDebug("{msg}", msg);
            return OperationResult.Success(msg);

        }
        #endregion

        #endregion

        #region "受保护方法"
        #region "获取当前用户标识"
        /// <summary>
        /// 获取当前用户标识
        /// </summary>
        /// <returns></returns>
        protected string GetCurrentUserKey()
        {
            //获取用户Id信息
            string userKey = Principal.Identity.GetUserId();
            userKey = userKey.IsMissing() ? KeyConstants.AnonymousUser : userKey;
            return userKey;
        }
        #endregion

        #endregion

    }

}
